import queue
import threading
import time
import traceback  # 添加在文件顶部
from DrissionPage import Chromium, ChromiumOptions, SessionOptions
from DrissionPage.common import Settings
from create_creative import create_creative_func
from email_permission import email_list
from DrissionPage.common import Keys
from read_search_file import get_complete_sheet1, get_search_comp, get_set_note_ids
from create_unit import create_unit
from loguru import logger
from datetime import datetime
from DataRecorder import Recorder

lock = threading.Lock()
Settings.set_language("zh_cn")
co = ChromiumOptions(read_file=False)  # 不读取文件方式新建配置对象
so = SessionOptions(read_file=False)
browser = Chromium(addr_or_opts=co, session_options=so)

def log_message(log_callback, message, color=None):
    if callable(log_callback):
        log_callback(message, color) if color else log_callback(message)


def is_number(value):
    return type(value) in (int, float, complex)


def select_note_and_choose(note_id, u_view_tab):
    u_view_tab.ele('tag:span@@text()=添加笔记').click(by_js=True)
    note_id_arr = note_id.strip().split('\n')
    for note in note_id_arr:
        if u_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder^请输入笔记ID', timeout=2):
            u_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder^请输入笔记ID').run_js('this.value = arguments[0]; this.dispatchEvent(new Event("input"));', note)
            u_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder^请输入笔记ID').input(Keys.ENTER)
            u_view_tab.wait(1)
        if note_choose_ele := u_view_tab.ele('tag:span@@class$--color-primary --size-text-small@@text()=选择', timeout=3):
            note_choose_ele.click(by_js=True)  ## 选择笔记
    # 点击笔记选择，点击笔记确定
    u_view_tab.ele('css:.footer-actions > .--color-bg-primary').click(by_js=True)  # 笔记确定
# tag:div@@class=flexible@@text()=点击成本控制

def add_unit_id(plan_view_tab, row_excel, file_path, log_callback, df_sheet):
    # plan_view_tab.set.scroll.smooth(on_off=False)
    unit_id = row_excel['单元ID']
    unit_name = row_excel['单元名称']
    note_id = row_excel['笔记ID']
    plan_view_tab.wait.load_start()
    plan_view_tab.wait(2)

    # 批量添加笔记
    if plan_view_tab.ele('tag:span@@class$--size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()= 批量添加 ', timeout=2):
        plan_view_tab.ele('tag:span@@class$--size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()= 批量添加 ').parent(2).click(by_js=True)

        footer_container = plan_view_tab.ele('tag:div@@class=d-modal-footer')
        note_id_arr = note_id.strip().split('\n')
        plan_view_tab.ele('tag:input@@class=d-text@@type=text@@placeholder=回车输入多个 ID，最多 100 条').run_js('this.focus();')
        for note in note_id_arr:
            plan_view_tab.actions.input(note).input(Keys.ENTER)

        plan_view_tab.ele('tag:a@@class$--size-text-paragraph btn-validate@@text()=搜索').click(by_js=True)

        footer_container.ele('tag:span@@class$--size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=确认添加', timeout=2).parent(2).wait.enabled()
        footer_container.ele('tag:span@@class$--size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=确认添加', timeout=2).parent(2).click(by_js=True)

        # u_view_tab.ele('tag:span@@class$--size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=取消', timeout=2).parent(2).click()
        plan_view_tab.wait(1.5)
    else:
        note_id_arr = str(note_id).strip().split('\n')
        for i, note in enumerate(note_id_arr):
            select_note_and_choose(note, plan_view_tab)

    # 下一步
    plan_next_button_ele = plan_view_tab.ele('tag:span@@class$--size-text-paragraph d-text-nowrap d-text-ellipsis d-text-nowrap@@text()=保存').parent(2)
    plan_next_button_ele.scroll.to_see()
    # plan_next_button_ele.click(by_js=True)  # 点击下一步
    # 处理操作频繁
    handle_operate_too_fast(plan_next_button_ele, plan_view_tab, unit_name, log_callback)

    create_creative_func(plan_view_tab, row_excel, browser, file_path, plan_next_button_ele, log_callback)

def handle_operate_too_fast(plan_next_button_ele, plan_view_tab, unit_name, log_callback):
    max_retries = 10  # 最大重试次数
    retry_count = 0
    while retry_count < max_retries:
        # # 先检查是否已经进入下一页
        # if plan_view_tab.ele('tag:input@@class=d-text@@placeholder=请输入你的单元名称', timeout=2):  # 下一页的标识元素
        #     break
        plan_next_button_ele.click(by_js=True)

        if plan_view_tab.ele('@text():操作频繁', timeout=1):
            log_message(log_callback, f"保存单元名称:【{unit_name}】 - 触发操作频繁,正在重试({retry_count + 1}/{max_retries})", "red")
            logger.info(f"操作频繁，等待后重试 ({retry_count + 1}/{max_retries})")
            time.sleep(2 * (retry_count + 1))
            # try:
            #     plan_next_button_ele.click(by_js=True)
            # except NoRectError:
            #     log_message(log_callback, f"创建计划页面的下一步没有找到:{plan} - 页面已跳转，停止重试", "green")
            #     break
            retry_count += 1
        else:
            break

    if retry_count == max_retries:
        logger.error("已达到最大重试次数，仍然操作频繁")
        log_message(log_callback, f"计划名称: 【{unit_name}】 - 已达到最大重试次数，仍然操作频繁", "red")
    else:
        log_message(log_callback, f"计划名称【{unit_name}】-在重试({retry_count + 1}/{max_retries})次后成功执行下一步", "green")
        logger.info("操作成功执行")


'''点击新建计划'''
def insert_plan(row_excel, create_plan_tab, file_path, log_callback, df_sheet):
    unit_id = str(row_excel['单元ID']).strip()
    ignore_pop_ele = create_plan_tab.ele('@text()=暂时忽略', timeout=1)
    if ignore_pop_ele:
        ignore_pop_ele.click(by_js=True)

    create_plan_tab.ele('tag:span@@text()=单元').parent(5).click(by_js=True)
    create_plan_tab.wait(3)
    create_plan_tab.ele('tag:span@@class$--size-text-paragraph d-text-nowrap d-text-ellipsis@@text()=单元ID').run_js('this.click();')
    create_plan_tab.ele('tag:input@@class=d-text@@placeholder=请输入单元ID').input(unit_id, clear=True).input(Keys.ENTER)
    create_plan_tab.wait(1)
    try:
        lock.acquire()
        if create_plan_tab.ele(f'tag:span@@class$--color-text-paragraph --size-text-paragraph@@text()${unit_id}', timeout=2):
            unit_view_tab = create_plan_tab.ele(f'tag:span@@class$--color-text-paragraph --size-text-paragraph@@text()${unit_id}', timeout=2).parent(4).next().ele('tag:a@@text()=编辑').click.for_new_tab(by_js=True)
            unit_view_tab.wait.title_change("编辑单元 - 小红书聚光")
    finally:
        lock.release()

    add_unit_id(unit_view_tab, row_excel, file_path, log_callback, df_sheet)

# def handle_all_excel_data(df_sheet_info, file_path, log_callback=None):
#     for index, row in df_sheet_info.iterrows():
#         try:
#             log_message(log_callback, f"处理中: {row['计划名']}")
#             insert_plan(row, file_path)  # 调用函数并传入当前行数据
#         except Exception as e:
#             r = Recorder(f'error-{datetime.now().strftime("%Y-%m-%d")}.csv')
#             r.add_data([row['账号名称'], row['计划名'], datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str(e)])  # 添加数据
#             r.record()  # 记录数据
#             log_message(log_callback, f"执行错误: {row['计划名']}", "red") # 前端日志
#             logger.error(f"错误时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - 出错的行数据计划名:{row['计划名']} - 错误日志: {str(e)}")
#             continue
#
#     log_message(log_callback, f"所有计划执行完毕", "green")


def worker(task_queue, create_plan_tab, file_path, log_callback, df_sheet):
    """
    工作线程函数，从队列中获取任务并执行自动化操作
    """
    while True:
        row_excel = task_queue.get()
        if row_excel is None:  # 结束信号
            break
        try:
            log_message(log_callback, f"处理中: {row_excel['单元名称']}")
            insert_plan(row_excel, create_plan_tab, file_path, log_callback, df_sheet)
        except Exception as e:
            # 获取完整错误信息
            error_msg = f"{type(e).__name__}: {str(e)}"
            error_trace = traceback.format_exc()  # 获取完整堆栈跟踪
            # 前端显示简化错误
            log_message(log_callback, f"执行错误: {row_excel['单元名称']} - {error_msg}", "red")

            # 日志记录完整错误
            logger.error(f"错误时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
                         f"计划名: {row_excel['单元名称']}\n"
                         f"错误类型: {type(e).__name__}\n"
                         f"错误详情: {error_msg}\n"
                         f"堆栈跟踪:\n{error_trace}")
        finally:
            task_queue.task_done()
    log_message(log_callback, f"处理完毕", "green")  # 全部处理完毕

def start_sub_account_url(file_path, concurrency_num=2, log_callback=None):
    df_sheet = get_complete_sheet1(file_path)
    missing_ids = get_set_note_ids(df_sheet, file_path=file_path) # 主表中有但是附表中不存在的笔记ID

    if missing_ids:
        log_message(log_callback, f"以下笔记ID在转化组件中缺失: {', '.join(missing_ids)}, 补充必要笔记信息后再次运行", "red")
        return
    if int(concurrency_num) > 5:
        log_message(log_callback, f"并发数量暂时最大为5", "red")
        return
    if '封面全选' not in df_sheet.columns:
        log_message(log_callback, f"表格中缺少封面全选列", "red")
        return
    if '单元ID' not in df_sheet.columns:
        log_message(log_callback, f"表格中缺少单元ID列", "red")
        return

    task_queue = queue.Queue()
    # 将 Excel 数据逐行放入队列中
    for index, row in df_sheet.iterrows():
        task_queue.put(row)

    # 打开合作伙伴平台页面

    account_id = df_sheet['账号ID']
    text_account_id = account_id[0].strip()

    account_tab = browser.new_tab('https://partner.xiaohongshu.com/partner/subAccount-list')

    # TODO 加一个校验步骤， 不是叁柒的所属邮箱直接驳回
    account_tab.ele('tag:span@@class=d-text --color-static --color-text-paragraph --size-text-paragraph text label@@text()^登陆邮箱：').next().child().next().click(by_js=True)
    account_tab.wait(0.5)
    email_str = account_tab.ele('tag:span@@class=d-text --color-static --color-text-paragraph --size-text-paragraph text label@@text()^登陆邮箱：').next().child().text
    email_permission_list = email_list(log_callback)
    if email_str not in email_permission_list:
        log_message(log_callback, f"当前邮箱账号:【{email_str}】暂无权限使用", "red")
        return

    account_tab.ele('tag:input@@class=el-input__inner@@type=text@@autocomplete=off@@placeholder=请输入').input(text_account_id)
    account_tab.ele('tag:button@@id=search-btn--1').click(by_js=True)

    account_tab.wait(2)

    search_none_ele = account_tab.ele('tag:tr@@class=d-table__empty-row@@text()=暂无数据', timeout=0.5)
    if search_none_ele:
        log_message(log_callback, f"合作伙伴平台子账号ID:{text_account_id}搜索结果为空, 检查表格第一行子账号ID, 或者检查是否登录合作伙伴平台", "red")
        return

    account_tab.ele('tag:span@@text():跳转', timeout=2).hover()

    plan_tab_arr = []  # 新建计划标签页对象数组
    threads = []
    jg_ele = account_tab.ele('tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis@@text():聚光平台', timeout=2)

    if jg_ele:
        create_plan_tab = jg_ele.click.for_new_tab(by_js=True)
        create_plan_tab.wait.title_change("计划列表")

        plan_url = create_plan_tab.url
        print(f"点完聚光平台以后跳转的tab:{create_plan_tab.url}")
        plan_tab_arr.append(create_plan_tab) # 先把默认打开的标签页对象加进去

        if int(concurrency_num) > 1:
            for _ in range(concurrency_num - 1):
                plan_tab_arr.append(browser.new_tab(plan_url)) # 再开启额外的线程数量的标签页

    for plan_tab in plan_tab_arr:
        logger.info(f"开始创建线程: {threading.current_thread().name} - 给当前线程分配的新建计划tab标签页:{id(plan_tab)}")
        t = threading.Thread(target=worker, args=(task_queue, plan_tab, file_path, log_callback, df_sheet))
        t.start()
        time.sleep(2)
        threads.append(t)

    task_queue.join()

    # 发送结束信号给所有线程
    for _ in range(len(threads)):
        task_queue.put(None)

    # 等待所有线程结束
    for t in threads:
        t.join()

    # handle_all_excel_data(df_sheet, file_path, log_callback)


# if __name__ == '__main__':
#     start_sub_account_url()
















